package com.podium.web.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.podium.auth.utils.SecurityUtils;
import com.podium.comment.utils.StringUtils;
import com.podium.web.system.entity.SysMenu;
import com.podium.web.system.entity.SysRoleMenu;
import com.podium.web.system.entity.SysUserRole;
import com.podium.web.system.mapper.SysMenuMapper;
import com.podium.web.system.service.SysMenuService;
import com.podium.web.system.service.SysRoleMenuService;
import com.podium.web.system.service.SysUserRoleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 邵文泽
 * @description 系统菜单
 * @date Tue Apr 29 09:58:56 CST 2025
 */
@Slf4j
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {

    @Autowired
    private SysUserRoleService userRoleService;

    @Autowired
    private SysRoleMenuService roleMenuService;

    @Override
    public IPage<SysMenu> page(Page<SysMenu> page, SysMenu sysMenu) {
        QueryWrapper<SysMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(SysMenu::getDelFlag, 0)
                .eq(sysMenu.getParentId() != null, SysMenu::getParentId, sysMenu.getParentId())
                .like(StringUtils.hasLength(sysMenu.getName()), SysMenu::getName, sysMenu.getName())
                .eq(sysMenu.getMenuType() != null, SysMenu::getMenuType, sysMenu.getMenuType())
                .eq(sysMenu.getVisible() != null, SysMenu::getVisible, sysMenu.getVisible())
                .orderByAsc(SysMenu::getSort)
                .orderByDesc(SysMenu::getId)
        ;
        return super.page(page, queryWrapper);
    }

    @Override
    public List<SysMenu> list(SysMenu sysMenu) {
        QueryWrapper<SysMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(SysMenu::getDelFlag, 0)
                .eq(sysMenu.getParentId() != null, SysMenu::getParentId, sysMenu.getParentId())
                .like(StringUtils.hasLength(sysMenu.getName()), SysMenu::getName, sysMenu.getName())
                .eq(sysMenu.getMenuType() != null, SysMenu::getMenuType, sysMenu.getMenuType())
                .eq(sysMenu.getVisible() != null, SysMenu::getVisible, sysMenu.getVisible())
        ;
        return super.list(queryWrapper);
    }

    @Override
    public List<SysMenu> treeList(SysMenu sysMenu) {
        if (sysMenu.getParentId() == null && !StringUtils.hasLength(sysMenu.getName()) && sysMenu.getMenuType() == null && sysMenu.getVisible() == null) {
            sysMenu.setParentId(0L);
        }
        QueryWrapper<SysMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(SysMenu::getDelFlag, 0)
                .eq(sysMenu.getParentId() != null, SysMenu::getParentId, sysMenu.getParentId())
                .like(StringUtils.hasLength(sysMenu.getName()), SysMenu::getName, sysMenu.getName())
                .eq(sysMenu.getMenuType() != null, SysMenu::getMenuType, sysMenu.getMenuType())
                .eq(sysMenu.getVisible() != null, SysMenu::getVisible, sysMenu.getVisible())
                .orderByAsc(SysMenu::getSort)
                .orderByDesc(SysMenu::getId);

        return getTreeList(queryWrapper, sysMenu);
    }

    public List<SysMenu> getTreeList(QueryWrapper<SysMenu> queryWrapper, SysMenu query) {
        List<SysMenu> list = super.list(queryWrapper);
        for (SysMenu sysMenu : list) {
            queryWrapper.clear();
            queryWrapper.lambda().eq(SysMenu::getDelFlag, 0)
                    .eq(SysMenu::getParentId, sysMenu.getId())
                    .like(StringUtils.hasLength(query.getName()), SysMenu::getName, query.getName())
                    .eq(query.getMenuType() != null, SysMenu::getMenuType, query.getMenuType())
                    .eq(query.getVisible() != null, SysMenu::getVisible, query.getVisible())
                    .orderByAsc(SysMenu::getSort)
                    .orderByDesc(SysMenu::getId);
            long count = super.count(queryWrapper);
            if (count > 0) {
                sysMenu.setChildren(getTreeList(queryWrapper, query));
            }
        }
        return list;
    }

    @Override
    public SysMenu getById(Long id) {
        return super.getById(id);
    }

    @Override
    public boolean save(SysMenu sysMenu) {
        sysMenu.setDelFlag(0L);
        sysMenu.setCreateBy(SecurityUtils.getUsername());
        sysMenu.setCreateTime(LocalDateTime.now());
        return super.save(sysMenu);
    }

    @Override
    public boolean updateById(SysMenu sysMenu) {
        sysMenu.setUpdateBy(SecurityUtils.getUsername());
        sysMenu.setUpdateTime(LocalDateTime.now());
        return super.updateById(sysMenu);
    }

    @Override
    public void removeById(Long id) {
        super.removeById(id);
    }

    @Override
    public List<SysMenu> listByIds(Set<Long> menuIds) {
        return super.listByIds(menuIds);
    }

    @Override
    public List<SysMenu> getByUserMenus(Long userId) {
        // 超级管理员拥有所有菜单权限
        if (userId == 1L) {
            LambdaQueryWrapper<SysMenu> wrapper = new QueryWrapper<SysMenu>().lambda()
                    .eq(SysMenu::getDelFlag, 0)
                    .in(SysMenu::getMenuType, 1, 2)
                    .orderByAsc(SysMenu::getSort)
                    .orderByDesc(SysMenu::getId);
            List<SysMenu> allMenus = super.list(wrapper);
            return buildMenuTree(allMenus);
        }
        SysUserRole sysUserRole = new SysUserRole();
        sysUserRole.setUserId(userId);
        // 获取用户角色ID集合
        List<Long> roleIds = userRoleService.list(sysUserRole)
                .stream()
                .map(SysUserRole::getRoleId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());

        if (roleIds.isEmpty()) {
            return List.of();
        }

        // 获取角色关联的菜单ID集合
        List<Long> menuIds = roleMenuService.listByRoleId(roleIds)
                .stream()
                .map(SysRoleMenu::getMenuId)
                .distinct()
                .collect(Collectors.toList());

        if (menuIds.isEmpty()) {
            return List.of();
        }

        // 查询所有有效的菜单
        LambdaQueryWrapper<SysMenu> queryWrapper = new QueryWrapper<SysMenu>().lambda()
                .in(SysMenu::getId, menuIds)
                .eq(SysMenu::getDelFlag, 0)
                .eq(SysMenu::getVisible, 0)
                .in(SysMenu::getMenuType, 2)
                .orderByAsc(SysMenu::getSort)
                .orderByDesc(SysMenu::getId);

        List<SysMenu> menus = super.list(queryWrapper);
        queryWrapper.clear();

        queryWrapper
                .in(SysMenu::getId, menus.stream().map(SysMenu::getParentId).collect(Collectors.toSet()))
                .eq(SysMenu::getDelFlag, 0)
                .eq(SysMenu::getVisible, 0)
                .in(SysMenu::getMenuType, 1)
                .orderByAsc(SysMenu::getSort)
                .orderByDesc(SysMenu::getId);
        menus.addAll(super.list(queryWrapper));
        return buildMenuTree(menus);
    }


    /**
     * 构建菜单树
     */
    private List<SysMenu> buildMenuTree(List<SysMenu> menus) {
        // 构建 id -> menu 映射，方便查找
        Map<Long, SysMenu> menuMap = menus.stream()
                .collect(Collectors.toMap(SysMenu::getId, m -> m));

        // 找出所有父节点（即 parentId = 0）
        List<SysMenu> rootMenus = menus.stream()
                .filter(menu -> menu.getParentId() == null || menu.getParentId() == 0)
                .sorted(
                        Comparator.comparing(SysMenu::getSort, Comparator.reverseOrder())
                                .thenComparing(SysMenu::getId)
                                .reversed()
                )
                .toList();

        // 遍历菜单，构建父子关系
        for (SysMenu menu : menus) {
            Long parentId = menu.getParentId();
            if (parentId != null && parentId > 0 && menuMap.containsKey(parentId)) {
                SysMenu parent = menuMap.get(parentId);
                if (parent.getChildren() == null) {
                    parent.setChildren(new ArrayList<>());
                }
                parent.getChildren().add(menu);
            }
        }

        return rootMenus;
    }

}